package petertel.pbx.connector;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

public class Connection implements IConnection {

	private Session session;

	public void connect(String username, String password, String hostname,
			int port) {
		try {
			JSch jsch = new JSch();
			session = jsch.getSession(username, hostname, port);
			session.setUserInfo(USER_INFO);
			session.setPassword(password);
			session.setDaemonThread(true);
			session.connect();
		} catch (JSchException e) {
			throw new RuntimeException(e);
		}
	}

	public IResult execute(String command) {
		final StringBuilder stdout = new StringBuilder();
		final StringBuilder stderr = new StringBuilder();
		final int status = execute(command, new IShellCallback() {

			public boolean processStdout(String line) {
				stdout.append(line);
				stdout.append('\n');
				return true;
			}

			public boolean processStderr(String line) {
				stderr.append(line);
				stderr.append('\n');
				return true;
			}

			public boolean isClosed() {
				return false;
			}

		});
		return new IResult() {

			public String getStdout() {
				return stdout.toString();
			}

			public String getStderr() {
				return stderr.toString();
			}

			public int getStatus() {
				return status;
			}

			@Override
			public String toString() {
				return "<status:" + getStatus() + "><stdout:" + getStdout()
						+ "><stderr:" + getStderr() + ">";
			}

		};
	}

	public int execute(String command, IShellCallback callback) {
		try {
			ChannelExec channel = (ChannelExec) session.openChannel("exec");
			channel.setCommand(command);
			channel.setInputStream(null);
			InputStream out = channel.getInputStream();
			BufferedReader outBreader = new BufferedReader(
					new InputStreamReader(out));
			channel.setErrStream(null);
			InputStream err = channel.getErrStream();
			BufferedReader errBreader = new BufferedReader(
					new InputStreamReader(err));
			int status = -1977;
			channel.connect();
			outer: while (true) {
				while (true) {
					String line = outBreader.readLine();
					if (line == null) {
						break;
					}
					if (!callback.processStdout(line))
						break outer;
				}
				while (true) {
					String line = errBreader.readLine();
					if (line == null) {
						break;
					}
					if (!callback.processStderr(line))
						break outer;
				}
				if (channel.isClosed()) {
					status = channel.getExitStatus();
					break;
				}
				Thread.sleep(100);
			}
			channel.disconnect();
			return status;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void connect(String username, String password, String hostname) {
		connect(username, password, hostname, 22);
	}

	public void disconnect() {
		session.disconnect();
	}

	private static final UserInfo USER_INFO = new UserInfo() {
		public String getPassword() {
			return null;
		}

		public boolean promptYesNo(String str) {
			return true;
		}

		public String getPassphrase() {
			return null;
		}

		public boolean promptPassphrase(String message) {
			return true;
		}

		public boolean promptPassword(String message) {
			return false;
		}

		public void showMessage(String message) {
			;
		}

	};

}
